#include "stdafx.h"
#include "ui_freetype_render_util.h"
#include "ui_gdiplus_render_util.h"

_SSL_BEGIN
_SSUIL_BEGIN

void UIFreetypeRenderUtil::DrawText(UIFreetypeFontManager *font_manager, HDC dc, const tchar *text, int text_len,
	unsigned long text_color, const UIRect *rt, const tstring& font_id, unsigned int style,
	bool transparent, unsigned long bk_color /*= 0*/)
{
	if(font_manager == NULL)
		return;
	if(text == NULL || text_len == 0)
		return;
	if(rt == NULL || rt->Width() == 0 || rt->Height() == 0)
		return;

	UIRect rt_canvas(0, 0, rt->Width(), rt->Height());

	UIFtMaskImage mask_img;
	if(!MaskText(mask_img, font_manager, text, text_len, rt_canvas.Width(), rt_canvas.Height(), font_id, style,
		false, NULL))
		return;

	Gdiplus::Bitmap* bitmap_plus = new Gdiplus::Bitmap(rt_canvas.Width(), rt_canvas.Height(),
		PixelFormat32bppARGB);
	if(bitmap_plus == NULL || bitmap_plus->GetLastStatus() != 0)
	{
		return;
	}
	DWORD alpha_value = 0;
	COLORREF clr = DWORD2RGB(text_color, &alpha_value);

	Gdiplus::BitmapData datas;
	Gdiplus::Rect rc(0, 0, rt_canvas.Width(), rt_canvas.Height());
	bitmap_plus->LockBits(&rc, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &datas);
	byte *dest = (byte*)(datas.Scan0);
	for(int y=0; y<rt_canvas.Height(); y++)
	{
		for(int x=0; x<rt_canvas.Width(); x++)
		{
			byte *s_p = dest + y * rt_canvas.Width() * 4 + x * 4;
			s_p[0] = GetBValue(clr); // B
			s_p[1] = GetGValue(clr); // G
			s_p[2] = GetRValue(clr); // R
			s_p[3] = mask_img.buffer.ptr()[y * rt_canvas.Width() + x];
		}
	}

	bitmap_plus->UnlockBits(&datas);

	UIGdiplusRenderUtil::DrawImage(dc, bitmap_plus, NULL, *rt, 0, 0, alpha_value);

	delete bitmap_plus;
}

bool UIFreetypeRenderUtil::MeasureTextSize(UIFreetypeFontManager *font_manager, const tchar *text, int text_len,
	ss_inout_ UIRect &rt, const tstring& font_id, UIMeasureTextType measure_type)
{
	if(font_manager == NULL)
		return false;
	if(text == NULL || text_len == 0)
		return false;

#define kMaxCanvasLength 40960
	int width_limit = kMaxCanvasLength, height_limit = kMaxCanvasLength;
	int style = 0;
	switch(measure_type)
	{
	case kMeasureWidthAndHeightNoSingleLine:
		break;
	case kMeasureWidthAndHeight:
		style = kTextStyleSingleLine;
		break;
	case kMeasureHeight:
		if(rt.Width() > 0)
		{
			width_limit = rt.Width();
		}
		break;
	default:
		return false;
	}

	UIFtMaskImage mask_img;
	UISize st;
	if(!MaskText(mask_img, font_manager, text, text_len, width_limit, height_limit, font_id, style,
		true, &st))
		return false;
	rt.right = rt.left + st.cx;
	rt.bottom = rt.top + st.cy;

	return true;
}

bool UIFreetypeRenderUtil::GenerateMaskImage(int width, int height, UIFtMaskImage &mask_img)
{
	mask_img.width = width;
	mask_img.height = height;
	unsigned char *buffer = mask_img.buffer.alloc_ptr(width * height);
	memset(buffer, 0, width * height);
	return true;
}

bool UIFreetypeRenderUtil::RenderCharOnMaskImage(UIFreetypeFontManager *font_manager,
	UIFtMaskImage &mask_img, int x, int y, const UIFtCharInfo &ch)
{
	if(font_manager == NULL)
		return false;

	UIFtCharImgInfo *font_img_info = font_manager->GetCharImage(ch);
	if(font_img_info == NULL)
		return false;
	return RenderCharOnMaskImage(font_img_info, mask_img, x, y);
}

bool UIFreetypeRenderUtil::RenderCharOnMaskImage(UIFtCharImgInfo *ch_img_info, 
	UIFtMaskImage &mask_img, int x, int y)
{
	if(ch_img_info == NULL)
		return false;
	int mask_off_x = x, mask_off_y = y;
	int ft_width = ch_img_info->slot_width, ft_height = ch_img_info->slot_height;
	int off_x = 0, off_y = 0;
	if(mask_off_x < 0)
	{
		ft_width += mask_off_x;
		off_x -= mask_off_x;
		mask_off_x = 0;
	}
	if(mask_off_x + ft_width > mask_img.width)
		ft_width = mask_img.width - mask_off_x;

	if(mask_off_y < 0)
	{
		ft_height += mask_off_y;
		off_y -= mask_off_y;
		mask_off_y = 0;
	}
	if(mask_off_y + ft_height > mask_img.height)
		ft_height = mask_img.height - mask_off_y;

	if(ft_width > 0 && ft_height > 0)
	{
		for(int i=0; i<ft_height; i++)
		{
			memcpy(&(mask_img.buffer.ptr()[(mask_off_y + i) * mask_img.width + mask_off_x]), 
				&ch_img_info->img_buffer.ptr()[(off_y + i) * ch_img_info->slot_width + off_x],
				ft_width);
		}
	}
	return true;
}

bool UIFreetypeRenderUtil::MaskText(ss_out_ UIFtMaskImage &mask_image, UIFreetypeFontManager *font_manager,
	const tchar *text, int text_len, int canvas_width, int canvas_height,
	const tstring& font_id, unsigned int style, bool measure_size, UISize *layout_size)
{
	if(font_manager == NULL)
		return false;
	if(text == NULL || text_len == 0)
		return false;
	if(text_len >= (int)_tcslen(text))
		text_len = (int)_tcslen(text);

	UIFtFontIdInfo id_info;
	if(!font_manager->GetFontInfo(font_id, id_info))
		return false;

	UIFtCharInfo ch_info;
	ch_info.font_id_info = id_info;

	struct char_layout_info
	{
		int x;
		int y;
		UIFtCharImgInfo *img;
		int ch;
		char_layout_info()
		{
			this->x = 0;
			this->y = 0;
			this->img = NULL;
			this->ch = 0;
		}
		char_layout_info(int x, int y, UIFtCharImgInfo *img, int ch)
		{
			this->x = x;
			this->y = y;
			this->img = img;
			this->ch = ch;
		}
	};
	typedef std::vector<char_layout_info> char_layout_infos;

	ch_info.ch = _T('A');
	UIFtCharImgInfo *def_char_img_info = font_manager->GetCharImage(ch_info);
	if(def_char_img_info == NULL)
	{
		return false;
	}

	char_layout_infos c_layout_infos;
	char_layout_infos c_line_infos;
	int limit_width = canvas_width, limit_height = canvas_height;
	int x_offset = 0, x_offset_max = 0;
	int y_offset_b = 0, y_offset_e = 0;
	for(int i=0; i<text_len;i++)
	{
		if(y_offset_b > limit_height)
			break;

		char_layout_info clayouti;
		clayouti.ch = text[i];
		clayouti.x = x_offset;
		clayouti.y = y_offset_b;

		if(clayouti.ch == _T('\r') || clayouti.ch == _T('\n'))
		{
			if(SS_FLAG_ISSET(style, kTextStyleSingleLine))
				continue;
			goto next_line;
		}else if(clayouti.ch == _T('\t'))
		{
			if(x_offset + 4 * def_char_img_info->slot_width <= limit_width)
			{
				x_offset += 4 * def_char_img_info->slot_width;
				continue;
			}
			x_offset = limit_width;
			goto next_line;
		}

		ch_info.ch = text[i];
		clayouti.img = font_manager->GetCharImage(ch_info);
		if(clayouti.img == NULL)
		{
			if(i == text_len - 1)
				goto next_line;
			continue;
		}
		SS_ASSERT(clayouti.img->slot_width > 0 && clayouti.img->slot_height > 0);

		if(x_offset + clayouti.img->slot_width <= limit_width)
		{
			x_offset += clayouti.img->slot_width;
			if(y_offset_e - y_offset_b < clayouti.img->slot_height)
				y_offset_e = y_offset_b + clayouti.img->slot_height;
			if(!measure_size)
				c_line_infos.push_back(clayouti);
			if(i == text_len - 1)
				goto next_line;
			continue;
		}

		if(x_offset == 0)
		{
			x_offset = limit_width;
			if(!measure_size)
				c_line_infos.push_back(clayouti);
			goto next_line;
		}

		i--;
next_line:
		int line_height = y_offset_e - y_offset_b;
		SS_ASSERT(x_offset <= limit_width);
		if(x_offset_max < x_offset)
			x_offset_max = x_offset;
		if(!measure_size)
		{
			int line_x_offset = (limit_width - x_offset);
			for(char_layout_infos::iterator iter=c_line_infos.begin(); iter!=c_line_infos.end(); iter++)
			{
				if(iter->img->slot_height < line_height)
				{
					iter->y = y_offset_e - iter->img->slot_height;
				}

				if(line_x_offset == 0)
					continue;

				if(SS_FLAG_ISSET(style, kTextStyleRight))
				{
					iter->x += line_x_offset;
				}else if(SS_FLAG_ISSET(style, kTextStyleCenter))
				{
					iter->x += line_x_offset / 2;
				}
			}
			c_layout_infos.insert(c_layout_infos.end(), c_line_infos.begin(), c_line_infos.end());
			c_line_infos.clear();
		}

		y_offset_b = y_offset_e;
		x_offset = 0;
		if(SS_FLAG_ISSET(style, kTextStyleSingleLine))
			break;
		continue;
	}

	if(layout_size != NULL)
	{
		layout_size->cx = x_offset_max + 1;
		layout_size->cy = y_offset_e + 1;
	}
	if(measure_size)
	{
		return true;
	}

	if(y_offset_e < limit_height)
	{
		int layout_y_offset = 0;
		if(SS_FLAG_ISSET(style, kTextStyleVCenter))
			layout_y_offset = (limit_height - y_offset_e) / 2;
		else if(SS_FLAG_ISSET(style, kTextStyleBottom))
			layout_y_offset = (limit_height - y_offset_e);
		if(layout_y_offset > 0)
		{
			for(char_layout_infos::iterator iter=c_layout_infos.begin(); iter!=c_layout_infos.end(); iter++)
			{
				iter->y += layout_y_offset;
			}
		}
	}

	if(!GenerateMaskImage(canvas_width, canvas_height, mask_image))
		return false;
	for(char_layout_infos::iterator iter=c_layout_infos.begin(); iter!=c_layout_infos.end(); iter++)
	{
		RenderCharOnMaskImage(iter->img, mask_image, iter->x, iter->y);
	}
	return true;
}

_SSUIL_END
_SSL_END

